package com.example.demo.security.otp.api;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * HMAC（Hash-based Message Authentication Code）消息认证码类。
 * 用于生成基于哈希的消息认证码，以验证消息的完整性和来源。
 *
 * @author houp
 */
public class Hmac {

    /**
     * HMAC使用的哈希算法名称。
     */
    public static final String ALGORITHM = "RAW";

    private final Hash hash;
    private final byte[] secret;
    private final long currentInterval;

    /**
     * HMAC构造函数。
     *
     * @param hash            哈希算法对象。
     * @param secret          密钥，用于生成消息认证码。
     * @param currentInterval 当前时间间隔，可能用于生成与时间相关的挑战值。
     */
    public Hmac(Hash hash, byte[] secret, long currentInterval) {
        this.hash = hash;
        this.secret = secret;
        this.currentInterval = currentInterval;
    }

    /**
     * 生成消息认证码。
     *
     * @return 消息认证码字节数组。
     * @throws NoSuchAlgorithmException 如果指定的哈希算法不存在。
     * @throws InvalidKeyException      如果密钥无效。
     */
    public byte[] digest() throws NoSuchAlgorithmException, InvalidKeyException {
        // 根据当前时间间隔生成一个8字节的挑战值
        byte[] challenge = ByteBuffer.allocate(8).putLong(currentInterval).array();
        // 实例化MAC（Message Authentication Code）对象
        Mac mac = Mac.getInstance(hash.toString());
        // 创建密钥规范对象，使用密钥和算法
        SecretKeySpec macKey = new SecretKeySpec(secret, ALGORITHM);
        // 初始化MAC对象，使用指定的密钥
        mac.init(macKey);
        // 对挑战值进行哈希运算，生成消息认证码
        return mac.doFinal(challenge);
    }
}
